import html2canvas from "html2canvas";
import jsPDF from "jspdf";

/**
 * 导出 PDF
 * filename: 文件名
 * htmlDom: 通过 document.getElementById('') || document.querySelector('')
 * itemClassName：htmlDom 内的第一子元素共同的class名
 */

export function exportPDF(filename, htmlDom, itemClassName) {
  return new Promise((resolve, reject) => {
    // A4大小（毫米），210mm x 297mm
    const a4w = 197;
    const a4h = 297;
    // ##########################################获取当前屏幕对应的A4纸PX高度##########################################
    // A4高度转换成当前屏幕分辨率的px
    const inch = document.createElement("div");
    // 将div的高度设置为1英寸后，它会自动根据设备的分辨率进行缩放
    inch.style.cssText =
      "width:1in; height:1in; position:absolute; left:0px; top:0px; z-index:99; visibility:hidden;";
    document.body.appendChild(inch);
    const heightDpi = parseInt(inch.offsetHeight);
    document.body.removeChild(inch);
    // 将毫米转换为英寸, 再转换成px（后面减了250px，如果生成后的PDF还是有断层的情况，则调大这个值）
    const a4PxHeight =
      Math.round(((a4h / 25.4) * heightDpi * heightDpi) / 72) - 250;
    // ####################遍历每一个一级子元素，判断其后面是否追加空白子元素，防止出现元素出现在两张A4纸里面################
    if (itemClassName) {
      const childListID = htmlDom.getElementsByClassName(itemClassName);
      for (let i = 0; i < childListID.length; i++) {
        // 当前元素距离页面顶部的距离
        const offsetTop = childListID[i].offsetTop;
        // 当前元素高度
        const coffsetHeight = childListID[i].offsetHeight;
        // 高度 + 距离顶部距离 / A4纸px高度
        const topHeightRate = (offsetTop + coffsetHeight) / a4PxHeight;
        // 如果加上当前节点后，A4页显示不完
        if (topHeightRate > 1 && topHeightRate % 1 !== 0) {
          // 当前元素至顶部距离 / A4纸px高度
          const offsetTopRateStr = String(offsetTop / a4PxHeight);
          // 当前A4页也被占用的高度 = offsetTopRateStr只保留小数位 * A4纸px高度
          const alreadyOccupyH = Math.round(
            Number(
              "0" + offsetTopRateStr.substring(offsetTopRateStr.indexOf("."))
            ) * a4PxHeight
          );
          // 如果当前A4页高度占用 + 当前节点高度 > A4纸px高度，则追加空白节点
          if (alreadyOccupyH + coffsetHeight > a4PxHeight) {
            // 获取当前节点的父节点
            const divParent = childListID[i].parentNode;
            const newNode = document.createElement("div");
            // 追加节点高度为：A4纸px高度 - 当前页已占用
            newNode.style.height =
              Math.round(a4PxHeight - alreadyOccupyH) + "px";
            newNode.style.width = "100%";
            // 当前元素前插入空白节点
            divParent.insertBefore(newNode, childListID[i]);
          }
        }
      }
    }
    // ################################################开始导出########################################################
    html2canvas(htmlDom, {
      allowTaint: false,
      taintTest: false,
      logging: false,
      useCORS: true,
      dpi: 300,
      scale: 2, // 按比例增加分辨率
    }).then((canvas) => {
      // A4纸，纵向
      const pdf = new JsPDF("p", "mm", "a4");
      const ctx = canvas.getContext("2d");
      // 按A4显示比例换算一页图像的像素高度
      const imgHeight = Math.floor((a4h * canvas.width) / a4w);
      let renderedHeight = 0;
      while (renderedHeight < canvas.height) {
        const page = document.createElement("canvas");
        page.width = canvas.width;
        // 可能内容不足一页
        page.height = Math.min(imgHeight, canvas.height - renderedHeight);

        // 用getImageData剪裁指定区域，并画到前面创建的canvas对象中
        page.getContext("2d").putImageData(
            ctx.getImageData(
              0,
              renderedHeight,
              canvas.width,
              Math.min(imgHeight, canvas.height - renderedHeight)
            ),
            0,
            0
          );

        // 添加图像到页面，保留10mm边距
        pdf.addImage(
          page.toDataURL("image/jpeg", 1.0),
          "PNG",
          10,
          10,
          a4w,
          Math.min(a4h, (a4w * page.height) / page.width)
        );
        renderedHeight += imgHeight;
        if (renderedHeight < canvas.height) {
          // 如果后面还有内容，添加一个空页
          pdf.addPage();
        }
        // delete page
      }
      // 保存文件
      pdf.save(fileName + ".pdf");
      resolve();
    });
  });
}
